﻿using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Resources;
using System.Windows.Shapes;

namespace WPHttpServer
{
    public delegate HttpResponse HttpRequestHandler(HttpRequest request);

    public class HttpServer
    {
        public string Domain { get; private set; }
        public string ServiceName { get; set; }
        private readonly ConnectionManager _connectionManager;

        private readonly Dictionary<Regex, HttpRequestHandler> _requestHandlers;

        public ResourceManager ResourceManager { get; set; }

        public HttpRequestHandler Http404NotFoundResponse { get; set; }
        public HttpRequestHandler Http500InternalServerErrorResponse { get; set; }

        public HttpServer(string domain)
            : this(domain, "80")
        {

        }

        public HttpServer(string domain, string serviceName)
        {
            Domain = domain;
            ServiceName = serviceName;

            _requestHandlers = new Dictionary<Regex, HttpRequestHandler>();
            _connectionManager = new ConnectionManager(serviceName);
            _connectionManager.ConnectionReceived += ConnectionManagerOnConnectionReceived;
        }

        public void Start()
        {
            _connectionManager.StartListening();
        }

        private async Task<IEnumerable<byte>> ConnectionManagerOnConnectionReceived(byte[] incommingData)
        {
            HttpRequestParser requestParser = new HttpRequestParser(this);
            HttpRequest request = requestParser.Parse(incommingData);

            string requestedUri = request.Uri.AbsolutePath;

            HttpRequestHandler requestHandler = this._requestHandlers.Where(pair => pair.Key.IsMatch(requestedUri))
                                                                     .Select(pair => pair.Value)
                                                                     .FirstOrDefault();

            if (requestHandler == null && ResourceManager != null)
            {
                requestHandler = ResourceManager.GetContentAtUri(requestedUri);
            }

            if (requestHandler != null)
            {
                IEnumerable<byte> content;
                try
                {
                    HttpResponse response = requestHandler(request);
                    content = response.CreateResponseMessage();
                }
                catch
                {
                    content = this.GetHttp500Bytes(request);
                }

                return content;
            }
            else
            {
                return this.GetHttp404Bytes(request);
            }
        }

        private IEnumerable<byte> GetHttp404Bytes(HttpRequest request)
        {
            if (Http404NotFoundResponse == null)
            {
                return StandartHttpMessagesFactory.Error404NotFound.CreateResponseMessage();
            }
            else
            {
                try
                {
                    return Http404NotFoundResponse(request).CreateResponseMessage();
                }
                catch
                {
                    return this.GetHttp500Bytes(request);
                }
            }
        }

        private IEnumerable<byte> GetHttp500Bytes(HttpRequest request)
        {
            if (Http500InternalServerErrorResponse == null)
            {
                return StandartHttpMessagesFactory.Error500InternalServerError.CreateResponseMessage();
            }
            else
            {
                try
                {
                    return Http500InternalServerErrorResponse(request).CreateResponseMessage();
                }
                catch
                {
                    return StandartHttpMessagesFactory.Error500InternalServerError.CreateResponseMessage();
                }
            }
        }

        public void RegisterRequestHandler(Regex uriMatcher, HttpRequestHandler requestHandler)
        {
            _requestHandlers.Add(uriMatcher, requestHandler);
        }
    }
}
